<?php

/*
 * What php team is that is 'one thing, a team, work together'
 */

namespace App\Repositories;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;

class BaseRepository
{
    protected $model;

    public function __construct(Model $model)
    {
        $this->model = $model;
    }

    public function show(int $id)
    {
        return $this->model->find($id);
    }

    public function showOrFail(int $id, array $with = [], array $where = [])
    {
        return $this->model
            ->when(count($with), function ($query) use ($with) {
                return $query->with($with);
            })
            ->when(count($where), function ($query) use ($where) {
                foreach ($where as $k => $v) {
                    $query = $query->where($k, $v);
                }
                return $query;
            })
            ->find($id);
    }

    public function showByWhereOrFail(array $where, int $id)
    {
        return $this->model->where($where)->find($id);
    }

    public function showByWhere(array $where, array $with = [])
    {
        return $this->model
            ->when(count($with), function ($query) use ($with) {
                return $query->with($with);
            })
            ->when(count($where), function ($query) use ($where) {
                foreach ($where as $k => $v) {
                    if (is_array($v) && empty($v['condition'])) {
                        $query = $query->whereIn($k, $v);
                    } else {
                        if (is_array($v)){
                            $query = $query->where($k,$v['condition']  ,$v['value']);
                        }else{
                            $query = $query->where($k, $v);
                        }
                    }
                }
                return $query;
            })
            ->first();
    }

    public function showByWhereOrder(array $where, string $field, string $sorts = 'ASC', array $with = [])
    {
        return $this->model->where($where)->orderBy($field, $sorts)->first();
    }

    public function batchInsert(array $data, $where = [])
    {
        if ($where) {
            $this->deleteByWhere($where);
        }

        return $this->model->insert($data);
    }

    public function countByWhere($where, $groupBy = '', $query = [])
    {
        $betweenWhere = $query['betweenWhere'] ?? [];
        return $this->model
            ->when(count($where), function ($query) use ($where) {
                foreach ($where as $k => $v) {
                    if (is_array($v)) {
                        $query = $query->whereIn($k, $v);
                    } else {
                        $query = $query->where($k, $v);
                    }
                }

                return $query;
            })
            ->when(count($betweenWhere), function ($query) use ($betweenWhere) {
                foreach ($betweenWhere as $k => $v) {
                    $query->whereBetween($k, $v);
                }
                return $query;
            })
            ->when(!empty($groupBy), function ($query) use ($groupBy) {
                $query = $query->groupBy($groupBy);
                return $query;
            })
            ->count();
    }

    public function count()
    {
        return $this->model->count();
    }

    public function list(array $params = [])
    {
        $pageCount = $params['page_count'] ?? 50;
        $searchQuery = $params['query'] ?? '';
        $filterWhere = $params['filter_like_where'] ?? '';
        $page = $params['page'] ?? 1;
        $betweenWhere = $params['between_where'] ?? [];
        $groupByWhere = $params['group_by_where'] ?? '';
        $with = $params['with'] ?? [];
        $where = $params['where'] ?? [];
        $withCount = $params['with_count'] ?? [];
        $withChild = $params['with_child'] ?? [];
        $orderCondition = $params['order_condition'] ?? [];
        $limit = $params['limit'] ?? 0;
        $withWhere = $params['with_where'] ?? [];
        $withLikeWhere = $params['with_like_where'] ?? [];
        $whereHas = $params['with_has_where'] ?? [];
        $result = $this->model
            ->when($searchQuery, function ($query) use ($searchQuery) {
                return $query->where(function ($query) use ($searchQuery) {
                    $where = true;
                    foreach ($searchQuery as $k => $v) {
                        if ($where) {
                            $action = 'where';
                            $where = false;
                        } else {
                            $action = 'orWhere';
                        }
                        $query = $query->{$action}($k, 'like', '%' . $v . '%');
                    }

                    return $query;
                });
            })
            ->when($filterWhere, function ($query) use ($filterWhere) {
                return $query->where(function ($query) use ($filterWhere) {
                    $where = true;
                    foreach ($filterWhere as $k => $v) {
                        foreach ($v as $kk => $vv) {
                            if ($where) {
                                $action = 'where';
                                $where = false;
                            } else {
                                $action = 'orWhere';
                            }
                            $query = $query->{$action}($kk, 'like', '%' . $vv . '%');
                        }
                    }

                    return $query;
                });
            })
            ->when(count($with), function ($query) use ($with) {
                return $query->with($with);
            })
            ->when(count($withWhere), function ($query) use ($withWhere) {
                foreach ($withWhere as $key => $value) {
                    $query->with([$key => function ($query) use ($value) {
                        foreach ($value as $k => $v) {
                            if (is_array($v)) {
                                $query = $query->whereIn($k, $v);
                            } else {
                                $query = $query->where($k, $v);
                            }
                        }
                    }]);
                }
                return $query;
            })
            ->when(count($withLikeWhere), function ($query) use ($withLikeWhere) {
                foreach ($withLikeWhere as $key => $value) {
                    $query->with([$key => function ($query) use ($value) {
                        foreach ($value as $likeKey => $likeValue) {
                            $query->where($likeKey, 'like', "%$likeValue%");
                        }
                    }]);
                }
                return $query;
            })
            ->when(count($withChild), function ($query) use ($withChild) {
                return $query->with(['permissionList' => function ($query) use ($withChild) {
                    return $query->with($withChild);
                }]);
            })
            ->when(count($withCount), function ($query) use ($withCount) {
                return $query->withCount($withCount);
            })
            ->when(count($where), function ($query) use ($where) {
                foreach ($where as $k => $v) {
                    if (is_array($v)) {
                        $query = $query->whereIn($k, $v);
                    } else {
                        $query = $query->where($k, $v);
                    }
                }
                return $query;
            })
            ->when(count($betweenWhere), function ($query) use ($betweenWhere) {
                foreach ($betweenWhere as $k => $v) {
                    $query->whereBetween($k, $v);
                }
                return $query;
            })
            ->when(count($whereHas), function ($query) use ($whereHas) {
                foreach ($whereHas as $withKey => $withValue) {
                    return $query->wherehas($withKey,function ($query) use ($withValue) {
                        foreach ($withValue as $k => $v){
                            return $query->where($k,$v);
                        }
                    });
                }
            })
            ->when(count($orderCondition), function ($query) use ($orderCondition) {
                $query->orderBy($orderCondition[0], $orderCondition[1]);
                return $query;
            })
            ->when($limit, function ($query) use ($limit) {
                $query->take($limit);
            })
            ->when($pageCount, function ($query) use ($pageCount, $page) {
                return $query->paginate($pageCount);
            }, function ($query) {
                return $query->get();
            });
//            DB::connection()->enableQueryLog();
//            dd( DB::getQueryLog());
        return $result;
    }

    public function store($data)
    {
        $model = $this->model;
        $model->fill($data);
        $model->save();
        return $this->show($model->id);
    }

    public function getStoreId($data){
        $model = $this->model;
        return $model::insertGetId($data);
    }

    public function update($id, $data)
    {
        $model = $this->show(intval($id));
        foreach ($data as $k => $v) {
            $model->{$k} = $v;
        }
        $model->save();

        return $this->show($model->id);
    }

    public function batchUpdateByWhere($where, $data)
    {
        $model = $this->model;
        foreach ($where as $column => $value) {
            $model = is_array($value) ? $model->whereIn($column, $value) : $model->where($column, $value);
        }

        return $model->update($data);
    }

    public function delete($id)
    {
        return $this->model->destroy($id);
    }

    public function deleteByWhere($where)
    {
        return $this->model
            ->when(count($where), function ($query) use ($where) {
                foreach ($where as $k => $v) {
                    if (is_array($v)) {
                        $query = $query->whereIn($k, $v);
                    } else {
                        $query = $query->where($k, $v);
                    }
                }

                return $query;
            })
            ->delete();
    }

    public function deleteByWhereIn($field, $where)
    {
        return $this->model->whereIn($field, $where)->delete();
    }

}
